#include "NetworkInterface.h"
#include "BRE_EEG_dataStruct.h"
#include "ConfigImport.h"
#include "QString"
#include <vector>
#include <cmath>
#include <queue>
#include <algorithm>

NetworkInterface::NetworkInterface(QCustomPlot* plotWidget) : 
    networkPlot(plotWidget)
{
    // 显示相关性最大的前2.0%
    sparseDegree = ConfigImport::getInstance()->ntPercent;
    std::cout << "sparseDegree:" << sparseDegree << std::endl;
    // sparseDegree = 5.0;

    QPixmap backgroundPixmap(":/pic/pic/network_img.png");
    // QPixmap backgroundPixmap(":/pic/pic/black.png");
    networkPlot->axisRect()->setBackground(backgroundPixmap);
    // 设置轴范围
    networkPlot->xAxis->setRange(0, networkPlot->width());
    // 反转y轴,使得原点在左上角
    networkPlot->yAxis->setRange(0, networkPlot->height());
    networkPlot->yAxis->setRangeReversed(true);

    // 隐藏轴,网格和坐标尺
    networkPlot->xAxis->grid()->setVisible(false);
    networkPlot->yAxis->grid()->setVisible(false);
    networkPlot->xAxis->setVisible(false);
    networkPlot->yAxis->setVisible(false);
    networkPlot->xAxis->setTicks(false);
    networkPlot->yAxis->setTicks(false);

    // 背景透明
    networkPlot->setBackground(Qt::transparent);
    networkPlot->setStyleSheet("background: transparent;");
}

NetworkInterface::~NetworkInterface()
{
}

int NetworkInterface::get_LineNum(){
    return lines_vector.size();
}
/**********************************
 * 函数名：add_line
 * 功能：向lines_vector容器中添加直线
 * 输入：始点终点坐标
 * 输出：容器中直线的条数
 * 备注：无
**********************************/
int NetworkInterface::add_line(const uint16_t start_point[2], const uint16_t end_point[2]){
    if(start_point[0] == 0 || end_point[0] == 0){
        return lines_vector.size();
    }

    // 添加多条直线
    QCPItemLine *line = new QCPItemLine(networkPlot);
    // line->start->setCoords(EEGDEV::electrode_coordinate[5][0]+x_dev,EEGDEV::electrode_coordinate[5][1]+y_dev);
    // line->end->setCoords(EEGDEV::electrode_coordinate[3][0]+x_dev,EEGDEV::electrode_coordinate[3][1]+y_dev);
    line->start->setCoords(start_point[0],start_point[1]);
    line->end->setCoords(end_point[0],end_point[1]);

    // 设置直线的颜色和粗细
    QPen pen(Qt::red);
    pen.setWidth(3);
    line->setPen(pen);

    lines_vector.push_back(line); // 将直线指针存入容器
    return lines_vector.size();
}
/**********************************
 * 函数名：clear
 * 功能：清除之前的网络
 * 输入：无
 * 输出：无
 * 备注：无
**********************************/
void NetworkInterface::clear(){
    // 遍历并删除所有直线
    for (QCPItemLine *line : lines_vector) {
        networkPlot->removeItem(line);
    }
    lines_vector.clear(); // 清空容器
    networkPlot->replot();
}

/**********************************
 * 函数名：calculateIndices
 * 功能：根据索引k计算对应的通道对(i,j)
 * 输入：无
 * 输出：无
 * 备注：无
**********************************/
std::pair<int, int> NetworkInterface::calculateIndices(int k) {
    double sqrt_val = std::sqrt(1 + 8 * k);
    int j = static_cast<int>((3 + sqrt_val) / 2);
    int s = (j - 2) * (j - 1) / 2;

    // 调整j直到s <= k
    while (s > k) {
        j--;
        s = (j - 2) * (j - 1) / 2;
    }
    
    int i = k - s + 1;
    return {i, j};
}

/**********************************
 * 函数名：get_top_pairs
 * 功能：寻找相关系数最大值前n%的通道对
 * 输入：network：网路；percent：百分比
 * 输出：无
 * 备注：无
**********************************/
std::vector<std::pair<int, int>> NetworkInterface::get_top_pairs(const arma::rowvec& network, double percent){
    const arma::uword total = network.n_elem;
    if (total == 0 || percent <= 0) {
        std::cout << "In NetworkInterface::get_top_pairs, empty result." << std::endl;
        return {};
    }

    // 计算需要保留的元素数量,向上取整，小于1取1
    const arma::uword keep = std::max<arma::uword>(1, static_cast<arma::uword>(std::ceil(total * percent / 100.0)) );

    // 使用最小堆维护前k大元素（存储索引和绝对值）
    using HeapElement = std::pair<double, arma::uword>;
    auto cmp = [](const HeapElement& a, const HeapElement& b) {
        return a.first > b.first; // 最小堆比较器
    };

    // 创建了一个优先队列，降序排列
    std::priority_queue<HeapElement, std::vector<HeapElement>, decltype(cmp)> heap(cmp);

    // 单次遍历处理所有元素
    for (arma::uword idx = 0; idx < total; ++idx) {
        const double abs_val = std::abs(network[idx]);
        
        if (heap.size() < keep) {
            heap.emplace(abs_val, idx);
        } else if (abs_val > heap.top().first) {
            heap.pop();
            heap.emplace(abs_val, idx);
        }
    }

    // 转换为通道对
    std::vector<std::pair<int, int>> result;
    while (!heap.empty()) {
        auto pair = calculateIndices(heap.top().second);
        result.emplace_back(pair);
        heap.pop();
    }
    return result;
}

/**********************************
 * 函数名：findHighCorrelations
 * 功能：寻找相关系数超过阈值的通道对
 * 输入：无
 * 输出：无
 * 备注：无
**********************************/
std::vector<NetworkInterface::Pair> NetworkInterface::findHighCorrelations(const arma::rowvec& network, double threshold) {
    std::vector<NetworkInterface::Pair> result;
    for (arma::uword idx = 0; idx < network.n_elem; ++idx) {
        double value = network(idx);
        if (value > threshold) {
            int k = static_cast<int>(idx);
            double sqrt_val = std::sqrt(1 + 8 * k);
            int j = static_cast<int>((3 + sqrt_val) / 2);
            int s = (j - 2) * (j - 1) / 2;

            // 确保s <= k
            while (s > k) {
                j--;
                s = (j - 2) * (j - 1) / 2;
            }

            int i = k - s + 1;
            result.push_back({i, j});
        }
    }
    return result;
}

/**********************************
 * 函数名：networkCreate
 * 功能：从数据生成连线
 * 输入：无
 * 输出：无
 * 备注：无
**********************************/
void NetworkInterface::networkCreate(){
    if(!networkData.n_elem){
        std::cout << "In NetworkInterface::networkCreate, networkData is empty!" << std::endl;
        return; 
    }
    // auto pairs = findHighCorrelations(networkData, sparseDegree);
    auto pairs = get_top_pairs(networkData, sparseDegree);

    for (const auto& p : pairs) {
        add_line(EEGDEV::electrode_coordinate[p.first-1], EEGDEV::electrode_coordinate[p.second-1]);
        // std::cout << "对象" << p.first << " - 对象" << p.second << std::endl;
    }
}

/**********************************
 * 函数名：networkReplot
 * 功能：重画
 * 输入：无
 * 输出：无
 * 备注：无
**********************************/
void NetworkInterface::networkReplot(){
    networkPlot->replot();
}
